/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 *
 */

import os from 'os';
import util from 'util';

import { HvigorLogger } from '@ohos/hvigor';
import { LogEvent } from '@ohos/hvigor-arkts-compose';
import { HvigorOhosPluginAdaptor } from '@ohos/hvigor-logger';
import { Level, levels } from 'log4js';

import { ECM } from '../../error/error-code-map.js';
import { recordDECE } from '../../error/error-util.js';

/**
 * Hvigor-Ohos-Plugin的定制logger
 *
 * @since 2022/3/3
 */
export class OhosLogger extends HvigorLogger {
  private messageMap: Map<string, string> = new Map<string, string>();

  private errList: string[] = [];

  constructor(category?: string) {
    super(category);
  }

  /**
   * 获取对应类别的OhosLogger实例
   *
   * @param category 默认是default
   */
  public static getLogger(category?: string): OhosLogger {
    return this.getInstance(OhosLogger, category);
  }

  public static getLoggerWithDurationId(category: string, durationId: string): OhosLogger {
    const logger = { ...(super.getInstance(OhosLogger, category) as OhosLogger) };
    const ohosLogger: OhosLogger = Object.setPrototypeOf(logger, OhosLogger.prototype);
    ohosLogger.durationId = durationId;
    return ohosLogger;
  }

  _buildError(cause: string, errorCode?: string) {
    if (errorCode) {
      this.messageMap.set('code', errorCode);
    }
    this.messageMap.set('cause', cause);
    return this;
  }

  /**
   * use _detail instead
   *
   * @deprecated use _detail instead
   * @param solution
   */
  _solution(solution: string) {
    this.messageMap.set('solution', solution);
    return this;
  }

  _detail(detail: string) {
    this.messageMap.set('solution', detail);
    return this;
  }

  _help(help: string) {
    this.messageMap.set('help', help);
    return this;
  }

  _record() {
    const args: string[] = Array.from(this.messageMap.values());
    const err: string = util.format(this._formatLog('root'), ...args);
    this.messageMap.clear();
    this.errList.push(err);
  }

  _printAllExit() {
    if (this.errList.length === 0) {
      return;
    }
    for (let i = 0; i < this.errList.length - 1; i++) {
      this.error(this.errList[i]);
    }
    const last = this.errList[this.errList.length - 1];
    this.errList = [];
    this.errorMessageExit(last);
  }

  _format() {
    const args: string[] = Array.from(this.messageMap.values());
    const err: string = util.format(this._formatLog('root'), ...args);
    this.messageMap.clear();
    return err;
  }

  _file(file: string, line = -1, column = -1) {
    let str = `at ${file}`;
    if (line > 0) {
      str += `:${line}`;
      if (column > 0) {
        str += `:${column}`;
      }
    }
    this.messageMap.set('file', str);
    return this;
  }

  _callstack(callstack: string) {
    if (this.getLevel() === levels.DEBUG) {
      this.messageMap.set('callstack', callstack);
    }
    return this;
  }

  _printDebugCommand(toolName: string, command: string[] | object) {
    this.debug(`Use tool [${toolName}]\n`, command);
  }

  _printWarn(moduleName: string) {
    const values = Array.from(this.messageMap.values());
    this.warn(this._formatLog(moduleName), ...values);
  }

  _printError(moduleName: string) {
    const values = Array.from(this.messageMap.values());
    this.error(this._formatLog(moduleName), ...values);
  }

  _printErrorAndExit(moduleName = 'root') {
    const values = Array.from(this.messageMap.values());
    this.errorMessageExit(this._formatLog(moduleName), ...values);
  }

  private _formatLog(moduleName?: string): string {
    // 默认肯定存在cause, 如果存在code, 在cause前显示, cause和code特殊处理
    let format = this.messageMap.has('code') ? '[%s]%s' : '%s';

    for (const key of this.messageMap.keys()) {
      switch (key) {
        case 'solution':
          format += `${os.EOL}\t Detail: %s`;
          break;
        case 'help':
          format += `${os.EOL}\t Help: %s`;
          break;
        case 'file':
          format += `${os.EOL}\t %s`;
          break;
        case 'callstack':
          format += `${os.EOL + os.EOL}    %s`;
          break;
      }
    }
    this.messageMap.clear();
    return format;
  }

  _errorCode(dece: ECM.DECE) {
    recordDECE(dece);
    return this;
  }

  protected getAdaptor(errorId: string) {
    return new HvigorOhosPluginAdaptor(errorId);
  }
}

export const handleLogs = (logs: LogEvent[], logger: OhosLogger, level: Level) => {
  let warnMsg = '';
  let infoMsg = '';
  let debugMsg = '';
  const yellow = '\u001b[33m';
  const blue = '\u001b[34m';
  const reset = '\u001b[39m';

  logs
    .filter((le) => level.isLessThanOrEqualTo(le.level))
    .forEach((currentValue) => {
      if (currentValue.level === 'warn') {
        warnMsg += `${yellow}WARN: ${currentValue.msg}${reset}${os.EOL}`;
      }
      if (currentValue.level === 'info') {
        infoMsg += `${blue}INFO: ${currentValue.msg}${reset}${os.EOL}`;
      }
      if (currentValue.level === 'debug') {
        debugMsg += `DEBUG: ${currentValue.msg}${os.EOL}`;
      }
    });

  if (warnMsg !== '') logger.warn(warnMsg);
  if (infoMsg !== '') logger.info(infoMsg);
  if (debugMsg !== '') logger.debug(debugMsg);
};
